import random, sys, pygame
from pygame.locals import *

FPS = 30
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
BUTTONSIZE = 200
GAPSIZE = 20
FLASHDELAY = 200

XMARGIN = (WINDOWWIDTH - ( 2 * (BUTTONSIZE + GAPSIZE) )) // 2 + GAPSIZE//2
YMARGIN = (WINDOWHEIGHT - ( 2 * (BUTTONSIZE + GAPSIZE))) // 2 + GAPSIZE//2
YELLOW = (155,155,0)
BRIGHTYELLOW = (255,255,0)
BLUE = (0,0,155)
BRIGHTBLUE = (0,0,255)
RED = (155,0,0)
BRIGHTRED = (255,0,0)
GREEN = (0,155,0)
BRIGHTGREEN = (0,255,0)
BLACK = (0,0,0)
WHITE = (255,255,255)
YELLOWRECT = pygame.Rect(XMARGIN, YMARGIN, BUTTONSIZE, BUTTONSIZE)
BLUERECT = pygame.Rect(XMARGIN+BUTTONSIZE+GAPSIZE, YMARGIN, BUTTONSIZE, BUTTONSIZE)
REDRECT = pygame.Rect(XMARGIN, YMARGIN+BUTTONSIZE+GAPSIZE, BUTTONSIZE, BUTTONSIZE)
GREENRECT = pygame.Rect(XMARGIN+BUTTONSIZE+GAPSIZE, YMARGIN+BUTTONSIZE+GAPSIZE, BUTTONSIZE, BUTTONSIZE)
BASICFONTSIZE = 16
bgColor = BLACK
def changeBackgroundAnimation(animationSpeed=40):
    global bgColor
    newBgColor = tuple(random.randint(0,255) for i in range(3))
    newBgSurf = pygame.Surface((WINDOWWIDTH, WINDOWHEIGHT))
    newBgSurf = newBgSurf.convert_alpha()
    r, g, b = newBgColor
    for alpha in range(0, 255, animationSpeed):
        checkForQuit()
        DISPLAYSURF.fill(bgColor)
        newBgSurf.fill((r, g, b, alpha))
        DISPLAYSURF.blit(newBgSurf, (0, 0))
        drawButtons()
        pygame.display.update()
        FPSCLOCK.tick(FPS)
    bgColor = newBgColor
def gameOverAnimation(color=WHITE, animationSpeed=50):
    originalSurf = DISPLAYSURF.copy()
    flashSurf = pygame.Surface(DISPLAYSURF.get_size())
    flashSurf = flashSurf.convert_alpha()
    BEEP1.play()
    BEEP2.play()
    BEEP3.play()
    BEEP4.play()
    r, g, b = color
    for i in range(3):
        for start, end, step in ((0, 255, 1), (255, 0, -1)):
            for alpha in range(start, end, animationSpeed*step):
                checkForQuit()
                flashSurf.fill((r, g, b, alpha))
                DISPLAYSURF.blit(originalSurf, (0, 0))
                DISPLAYSURF.blit(flashSurf, (0, 0))
                drawButtons()
                pygame.display.update()
                FPSCLOCK.tick(FPS)
def flashButtonAnimation(color, animationSpeed = 50):
    if color == YELLOW:
        sound = BEEP1
        flashColor = BRIGHTYELLOW
        rectangle = YELLOWRECT
    elif color == BLUE:
        sound = BEEP2
        flashColor = BRIGHTBLUE
        rectangle = BLUERECT
    elif color == RED:
        sound = BEEP3
        flashColor = BRIGHTRED
        rectangle = REDRECT
    elif color == GREEN:
        sound = BEEP4
        flashColor = BRIGHTGREEN
        rectangle = GREENRECT
    
    originalSurf = DISPLAYSURF.copy()
    flashSurf = pygame.Surface((BUTTONSIZE, BUTTONSIZE))
    flashSurf = flashSurf.convert_alpha()
    r, g, b = flashColor
    sound.play()
    for start, end, step in ((0, 255, 1), (255, 0, -1)):
        for alpha in range(start, end, animationSpeed*step):
            checkForQuit()
            DISPLAYSURF.blit(originalSurf, (0, 0))
            flashSurf.fill((r, g, b, alpha))
            DISPLAYSURF.blit(flashSurf, rectangle.topleft)
            pygame.display.update()
            FPSCLOCK.tick(FPS)
    DISPLAYSURF.blit(originalSurf, (0, 0))
        
def getButtonClicked(x, y):
    if YELLOWRECT.collidepoint((x, y)):
        return YELLOW
    elif BLUERECT.collidepoint((x, y)):
        return BLUE
    elif REDRECT.collidepoint((x, y)):
        return RED
    elif GREENRECT.collidepoint((x, y)):
        return GREEN
    return None
def drawButtons():
    pygame.draw.rect(DISPLAYSURF, YELLOW, YELLOWRECT)
    pygame.draw.rect(DISPLAYSURF, BLUE, BLUERECT)
    pygame.draw.rect(DISPLAYSURF, RED, REDRECT)
    pygame.draw.rect(DISPLAYSURF, GREEN, GREENRECT)
    
def terminate():
    pygame.quit()
    sys.exit()
def checkForQuit():
    for event in pygame.event.get(QUIT):
        terminate()
    for event in pygame.event.get(KEYUP):
        if event.key == K_ESCAPE:
            terminate()
        pygame.event.post(event)


def simulate():
    global DISPLAYSURF, FPSCLOCK, BASICFONT, BEEP1, BEEP2, BEEP3, BEEP4
    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
    pygame.display.set_caption("模仿奏乐游戏")
    BASICFONT = pygame.font.SysFont('微软雅黑', BASICFONTSIZE, True)

    BEEP1 = pygame.mixer.Sound('res/beep1.mp3')
    BEEP2 = pygame.mixer.Sound('res/beep2.mp3')
    BEEP3 = pygame.mixer.Sound('res/beep3.mp3')
    BEEP4 = pygame.mixer.Sound('res/beep4.mp3')

    pattern = []
    currentStep = 0
    waitForInput = False
    score = 0

    while True:
        clickedButton = None
        DISPLAYSURF.fill(bgColor)
        drawButtons()

        scoreSurf = BASICFONT.render(str(score), 1, WHITE)
        scoreRect = scoreSurf.get_rect()
        #         scoreRect.topleft =((WINDOWWIDTH-scoreRect.width)//2, 5)
        scoreRect.center = (WINDOWWIDTH // 2, WINDOWHEIGHT // 2)

        DISPLAYSURF.blit(scoreSurf, scoreRect)
        checkForQuit()
        for event in pygame.event.get():
            if event.type == MOUSEBUTTONUP:
                mousex, mousey = event.pos
                clickedButton = getButtonClicked(mousex, mousey)
            elif event.type == KEYDOWN:
                if event.key == K_q:
                    clickedButton = YELLOW
                elif event.key == K_w:
                    clickedButton = BLUE
                elif event.key == K_a:
                    clickedButton = RED
                elif event.key == K_s:
                    clickedButton = GREEN
        if not waitForInput:
            pygame.display.update()
            pygame.time.wait(1000)
            pattern.append(random.choice((YELLOW, BLUE, RED, GREEN)))
            for button in pattern:
                flashButtonAnimation(button)
                pygame.time.wait(FLASHDELAY)
            waitForInput = True
        else:
            if clickedButton:
                if clickedButton == pattern[currentStep]:
                    flashButtonAnimation(clickedButton)
                    currentStep += 1

                    if currentStep == len(pattern):
                        changeBackgroundAnimation()
                        score += 1
                        waitForInput = False
                        currentStep = 0
                else:
                    gameOverAnimation()
                    pattern = []
                    currentStep = 0
                    waitForInput = False
                    score = 0
                    pygame.time.wait(1000)
                    changeBackgroundAnimation()
        pygame.display.update()
        FPSCLOCK.tick(FPS)
if __name__ == "__main__":
    simulate()